package com.navinfo.tripanalysis.util;

import com.navinfo.location.mileage.bean.MileageAndFuel;
import com.navinfo.location.mileage.bean.Point;
import com.navinfo.location.mileage.calculation.Calculation;
import com.navinfo.platform.score.TripScoreService;
import com.navinfo.platform.score.pojo.ScoreWeight;
import com.navinfo.tripanalysis.common.util.ArithmeticUtils;
import com.navinfo.tripanalysis.common.arithmetic.common.OuterStatisticData;
import com.navinfo.tripanalysis.common.util.DateUtils;
import com.navinfo.tripanalysis.pojo.Point0200;
import org.apache.commons.lang3.StringUtils;
import org.apache.spark.broadcast.Broadcast;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 *
 * @author 沈东生
 */
public class CommonUtils {
    private static final Logger logger = LoggerFactory.getLogger(CommonUtils.class);


    /**
     * 根据0200的点，获取精准后的里程油耗
     * @param points
     * @return
     */
    public static MileageAndFuel calcMileageFuel(List<Point0200> points) {
        List<Point> points1 = points.stream().map(point -> {
            Point p = new Point();
            p.setTid(point.getTid());
            p.setGpsDate(point.getGpsTime());
            p.setGpsMileage(point.getGpsMileage());
            p.setDiffFuelCons(point.getIntegralFuelCons());
            p.setDiffMileage(point.getIntegralMileage());
            p.setEcuMileage(point.getEcuMileage());
            p.setMeterMileage(point.getMeterMileage());
            p.setRotation(point.getRotation());
            p.setTotalFuelCons(point.getTotalFuelCons());
            p.setSerialNumber(point.getSerialNumber());
            p.setAcc(point.getAccStatus());
            return p;
        }).collect(Collectors.toList());
        return Calculation.getStdMilAndFuel4Df(points1);
    }

    /**
     * 计算行程开始和结束时的总里程、总油耗
     * @param m
     * @param points
     */
    public static void calcStartEndMileageFuel(OuterStatisticData m, List<Point0200> points) {
        if (CommonUtils.isCollectionEmpty(points)) {
            return;
        }

        //获取行程开始的位置点
        Point0200 validPoint = null;
        for (Point0200 p : points) {
            if (p.getStandardFuelCons() > 0 && p.getStandardMileage() > 0) {
                validPoint = p;
                break;
            }
        }

        //设置行程开始结束里程油耗
        //开始 0200标准总里程总油耗
        //结束 开始里程油耗+当前行程的里程油耗
        if (validPoint != null) {
            int startMileage = ArithmeticUtils.mileageKMToM(validPoint.getStandardMileage());
            int startFuel = ArithmeticUtils.fuelLToMl(validPoint.getStandardFuelCons());
            m.setRouteStartMileage(startMileage);
            m.setRouteStartFuel(startFuel);
            m.setRouteEndMileage(startMileage + m.getTripMileage());
            m.setRouteEndFuel(startFuel + m.getTripFuel());
        } else {
            logger.error("未找到有效的0200点，故不计算行程开始结束里程油耗");
        }
    }

    /**
     * 计算扩展的统计信息
     * @param m
     */
    public static void calcExtendInfo(OuterStatisticData m) {
        //精准cross_cities_detail中的里程油耗
        Optional.ofNullable(m.getCrossCitiesDetail()).ifPresent(a ->{
            a.forEach(e -> {
                e.setMileage(e.getMileage() + Optional.ofNullable(m.getRouteStartMileage()).orElse(0));
                e.setFuel(e.getFuel() + Optional.ofNullable(m.getRouteStartFuel()).orElse(0));
            });
        });

        //东风新增统计字段
        //百公里油耗，单位:L/100KM，trip_fuel*100/trip_mileage'
        //除不尽小数直接取整
        if(Optional.ofNullable(m.getTripMileage()).orElse(0).intValue() == 0 ){
            m.setFuel100KM(0);
        }else{
            m.setFuel100KM(BigDecimal.valueOf(Optional.ofNullable(m.getTripFuel()).orElse(0)*100)
                    .divide(BigDecimal.valueOf(m.getTripMileage()),0, BigDecimal.ROUND_UP).intValue());
        }

        //平均车速(不含怠速)，单位：KM/H，(trip_mileage/1000)/((trip_duration-idle_duration)/3600)
        BigDecimal durationDif = BigDecimal.valueOf(m.getTripDuration() - m.getIdleDuration()).divide(BigDecimal.valueOf(3600),2, BigDecimal.ROUND_UP);
        if(durationDif.doubleValue() < 0.0001 ){
            m.setAvgSpeedNoidle(0);
        }else{
            m.setAvgSpeedNoidle(BigDecimal.valueOf(m.getTripMileage()).divide(new BigDecimal("1000"),2,BigDecimal.ROUND_UP).divide(durationDif,0, BigDecimal.ROUND_UP).intValue());
        }

        //平均车速(含怠速) (trip_mileage/1000)/(trip_duration/3600)
        if(Optional.ofNullable(m.getTripDuration()).orElse(0).intValue() == 0){
            m.setAvgSpeed(0);
        }else{
            m.setAvgSpeed(BigDecimal.valueOf(m.getTripMileage())
                    .divide(new BigDecimal("1000"), 2,BigDecimal.ROUND_UP)
                    .divide(BigDecimal.valueOf(m.getTripDuration()).divide(BigDecimal.valueOf(3600),2,BigDecimal.ROUND_UP),0,BigDecimal.ROUND_UP).intValue());
        }

        //经济区间占比，单位：%，eco_driving_duration/trip_duration*100'
        if(Optional.ofNullable(m.getTripDuration()).orElse(0).intValue() == 0){
            m.setEcoProportion(0);
        }else{
            m.setEcoProportion(BigDecimal.valueOf(Optional.ofNullable(m.getEcoDrivingDuration()).orElse(0))
                    .divide(BigDecimal.valueOf(m.getTripDuration()),0, BigDecimal.ROUND_UP).intValue() * 100);
        }


        //刹车次数 "hsb_number+csb_number"'
        m.setBrakeTimes(Optional.ofNullable(m.getHsbNumber()).orElse(0) + Optional.ofNullable(m.getCsbNumber()).orElse(0) );

        //时间段百公里尿素消耗  100*尿素累计消耗/实际计算总里程 保留小数点后三位  单位 :L/100km
        if(Optional.ofNullable(m.getTripMileage()).orElse(0).intValue() == 0){
            m.setUrea100km(0L);
        }else{
            m.setUrea100km(remainTwoBit(Optional.ofNullable(m.getTripUrea()).orElse(0)*100,Long.valueOf(Optional.ofNullable(m.getTripMileage()).orElse(0))));
        }
//            m.setUrea100km(BigDecimal.valueOf(Optional.ofNullable(m.getTripUrea()).orElse(0) * 100 * 100)
//                    .divide(BigDecimal.valueOf(Optional.ofNullable(m.getTripMileage()).orElse(0)), 3, BigDecimal.ROUND_UP).doubleValue());
//        }
        //时间段尿燃比：尿素累计消耗（L）/实际计算总油耗（L） *100%。保留小数点后三位 单位: %
        if (Optional.ofNullable(m.getTripFuel()).orElse(0).intValue()==0){
            m.setUreaFuelRatio(0L);
        }else {
            m.setUreaFuelRatio(remainTwoBit(Optional.ofNullable(m.getTripUrea()).orElse(0)*100,Long.valueOf(Optional.ofNullable(m.getTripFuel()).orElse(0))));
//            m.setUreaFuelRatio(BigDecimal.valueOf(Optional.ofNullable(m.getTripUrea()).orElse(0) * 100 * 100)
//                    .divide(BigDecimal.valueOf(Optional.ofNullable(m.getTripFuel()).orElse(0)), 3, BigDecimal.ROUND_UP).doubleValue());
        }

    }

    /**
     * 计算行程打分
     * @param tripinfo
     * @param score
     */
    public static void calcTripScore (OuterStatisticData tripinfo, Broadcast<Map<String, ScoreWeight>> score){

        TripScoreService.init(score);
        Map<String,Integer> tripScoreMap = TripScoreService.calTripScoreMap(tripinfo, "", null);
        if(null!=tripScoreMap&&!tripScoreMap.isEmpty()){
            //综合得分
            tripinfo.setTotalScore(Optional.ofNullable(tripScoreMap.get("score")).orElse(0));
            //安全得分
            tripinfo.setSafeScore(Optional.ofNullable(tripScoreMap.get("safeScore")).orElse(0));
            //经济得分
            tripinfo.setEcoScore(Optional.ofNullable(tripScoreMap.get("ecoScore")).orElse(0));
        }

    }

    /**
     * 将list中的数据toString后用spliter作为分隔符，返回一个大的字符串
     *
     * @param list
     * @param spliter
     * @return
     */
    public static String mkString(Collection<?> list, String spliter) {
        StringBuilder stringBuilder = new StringBuilder();

        if(null!=list && list.size()>0){
            int i = 0;
            for (Object obj : list) {
                if (null != obj) {
                    if (i != 0) {
                        stringBuilder.append(spliter);
                    }
                    stringBuilder.append(obj);
                    i++;
                }
            }
        }

        return stringBuilder.toString();
    }

    /**
     * 判断集合是否为空
     * @param collection
     * @return
     */
    public static boolean isCollectionEmpty(Collection<?> collection) {
        return collection == null || collection.size() == 0;
    }

    /**
     * 判断集合不为空
     *
     * @param collection
     * @return
     */
    public static boolean isCollectionNotEmpty(Collection<?> collection) {
        return !isCollectionEmpty(collection);
    }

    public static Long remainTwoBit(double n, Long m){
        if( n == 0 || m == null || m == 0){
            return null;
        }
        return BigDecimal.valueOf(n).divide(BigDecimal.valueOf(m),2 , BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100)).longValue();
    }
}
